﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;

namespace SmartMathLibrary
{
    /// <summary>
    /// This class provides the formated printing of a matrix.
    /// </summary>
    [Serializable]
    public class MatrixPrinter
    {
        /// <summary>
        /// The source matrix to print.
        /// </summary>
        private Matrix sourceMatrix;

        /// <summary>
        /// Initializes a new instance of the <see cref="MatrixPrinter"/> class.
        /// </summary>
        /// <param name="sourceMatrix">The source matrix to print.</param>
        public MatrixPrinter(Matrix sourceMatrix)
        {
            if (sourceMatrix == (Matrix) null)
            {
                throw new ArgumentNullException("sourceMatrix");
            }

            this.sourceMatrix = sourceMatrix;
        }

        /// <summary>
        /// Gets or sets the source matrix to print.
        /// </summary>
        /// <value>The source matrix to print.</value>
        public Matrix SourceMatrix
        {
            get { return sourceMatrix; }
            set { sourceMatrix = value; }
        }

        /// <summary>
        /// Prints the specified matrix.
        /// </summary>
        /// <param name="elementSpaces">The number of spaces between the column elements.</param>
        /// <returns>The formeted matrix.</returns>
        public String PrintMatrix(int elementSpaces)
        {
            return this.PrintMatrix(elementSpaces, "", NumberFormatInfo.InvariantInfo);
        }

        /// <summary>
        /// Prints the specified matrix.
        /// </summary>
        /// <param name="format">A numeric format string.</param>
        /// <returns>The formeted matrix.</returns>
        public String PrintMatrix(String format)
        {
            return this.PrintMatrix(3, format, NumberFormatInfo.InvariantInfo);
        }

        /// <summary>
        /// Prints the specified matrix.
        /// </summary>
        /// <param name="numberFormatInfo">An System.IFormatProvider that supplies culture-specific
        /// formatting information.</param>
        /// <returns>The formeted matrix.</returns>
        public String PrintMatrix(NumberFormatInfo numberFormatInfo)
        {
            return this.PrintMatrix(3, "", numberFormatInfo);
        }

        /// <summary>
        /// Prints the specified matrix.
        /// </summary>
        /// <param name="elementSpaces">The number of spaces between the column elements.</param>
        /// <param name="numberFormatInfo">An System.IFormatProvider that supplies culture-specific
        /// formatting information.</param>
        /// <returns>The formeted matrix.</returns>
        public String PrintMatrix(int elementSpaces, NumberFormatInfo numberFormatInfo)
        {
            return this.PrintMatrix(elementSpaces, "", numberFormatInfo);
        }

        /// <summary>
        /// Prints the specified matrix.
        /// </summary>
        /// <param name="elementSpaces">The number of spaces between the column elements.</param>
        /// <param name="format">A numeric format string.</param>
        /// <param name="numberFormatInfo">An System.IFormatProvider that supplies culture-specific 
        /// formatting information.</param>
        /// <returns>The formeted matrix.</returns>
        public String PrintMatrix(int elementSpaces, String format, NumberFormatInfo numberFormatInfo)
        {
            String result = "";
            int[] columnItemLength = new int[this.sourceMatrix.Columns];

            for (int i = 0; i < this.sourceMatrix.Rows; i++)
            {
                for (int j = 0; j < this.sourceMatrix.Columns; j++)
                {
                    if (this.sourceMatrix.GetValueAtPosition(i, j).ToString(format, numberFormatInfo).Length >
                        columnItemLength[j])
                    {
                        columnItemLength[j] = this.sourceMatrix.GetValueAtPosition(i, j)
                            .ToString(format, numberFormatInfo).Length;
                    }
                }
            }

            for (int i = 0; i < this.sourceMatrix.Rows; i++)
            {
                for (int j = 0; j < this.sourceMatrix.Columns; j++)
                {
                    result += GenerateSpaces(columnItemLength[j]
                                             -
                                             this.sourceMatrix.GetValueAtPosition(i, j).ToString(format,
                                                                                                 numberFormatInfo).
                                                 Length);
                    result += this.sourceMatrix.GetValueAtPosition(i, j).ToString(format, numberFormatInfo)
                              + GenerateSpaces(elementSpaces);
                }

                result += "\n";
            }

            return result;
        }

        /// <summary>
        /// Generates a space string with a specified lenght.
        /// </summary>
        /// <param name="value">The number of required spaces.</param>
        /// <returns>The string, which inlucdes the specified number of spaces.</returns>
        private static String GenerateSpaces(int value)
        {
            String result = "";

            for (int i = 0; i < value; i++)
            {
                result += " ";
            }

            return result;
        }
    }
}